﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.ObjectBuilder2;
using Microsoft.Practices.Unity;

namespace Common.Unity.Extensions
{
	public static class IUnityContainerExtensions
	{
		/*public static ResultType Resolve<ResultType>( this IUnityContainer container, object source )
		{
			return (ResultType)Resolve( container, typeof(ResultType), null, source );
		}

		public static ResultType Resolve<ResultType>( this IUnityContainer container, string name, object source )
		{
			return (ResultType)Resolve( container, typeof(ResultType), name, source );
		}

		public static object Resolve( this IUnityContainer container, Type type, string name, object source )
		{
			Guard.ArgumentNotNull( source, "source" );

			var extension = container.Configure<CommonExtension>();
			if ( extension != null )
			{
				var result = extension.Resolve( type, name, source );
				return result;
			}
			throw new InvalidOperationException( "This container does not have the CommonExtension extension registered." );
		}*/

		public static IEnumerable<ObjectType> ResolveAllRegistered<ObjectType>( this IUnityContainer container )
		{
			var resolved = container.ResolveAll<ObjectType>();
			var registered = container.IsRegistered<ObjectType>( null );
			var result = registered ? resolved.Concat( new[]{ container.Resolve<ObjectType>() } ) : resolved;
			return result;
		}


		public static Type ResolveType<ObjectType>( this IUnityContainer container )
		{
			return ResolveType( container, typeof(ObjectType), null );
		}

		public static Type ResolveType<ObjectType>( this IUnityContainer container, string name )
		{
			return ResolveType( container, typeof(ObjectType), name );
		}

		public static Type ResolveType( this IUnityContainer container, Type type )
		{
			return ResolveType( container, type, null );
		}

		public static Type ResolveType( this IUnityContainer container, Type type, string name )
		{
			Guard.ArgumentNotNull( type, "type" );
			var extension = container.Configure<CommonExtension>();
			if ( extension != null )
			{
				Type result;
				if ( extension.MappedTypes.TryGetValue( new NamedTypeBuildKey( type, name ), out result ) )
				{
					return result;
				}
				var registered = container.IsRegistered( type, name );
				return registered ? type : null;
			}
			return null;
		}

		public static IEnumerable<Type> ResolveMappings<ObjectType>( this IUnityContainer container )
		{
			return ResolveMappings( container, typeof(ObjectType), null );
		}

		public static IEnumerable<Type> ResolveMappings<ObjectType>( this IUnityContainer container, string name )
		{
			return ResolveMappings( container, typeof(ObjectType), name );
		}

		public static IEnumerable<Type> ResolveMappings( this IUnityContainer container, Type type )
		{
			return ResolveMappings( container, type, null );
		}

		public static IEnumerable<Type> ResolveMappings( this IUnityContainer container, Type type, string name )
		{
			Guard.ArgumentNotNull( type, "type" );
			var extension = container.Configure<CommonExtension>();
			if ( extension != null )
			{
				List<Type> result;
				if ( extension.Mappings.TryGetValue( new NamedTypeBuildKey( type, name ), out result ) )
				{
					return result;
				}
			}
			return new Type[0];
		}

		public static bool IsRegistered<ObjectType>( this IUnityContainer container )
		{
			return container.IsRegistered( typeof(ObjectType), null );
		}

		public static bool IsRegistered<ObjectType>( this IUnityContainer container, string name )
		{
			return container.IsRegistered( typeof(ObjectType), name );
		}

		public static bool IsRegistered( this IUnityContainer container, Type type )
		{
			return container.IsRegistered( type, null );
		}

		public static bool IsRegistered( this IUnityContainer container, Type type, string name )
		{
			var extension = container.Configure<CommonExtension>();
			if ( extension == null )
			{
				container.AddExtension( extension = new CommonExtension() );
			}
			return extension.Items.Any( item => item.Type == type && item.Name == name );
		}
	}
}